package com.wxy.favorites.controller;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import com.wxy.favorites.constant.PublicConstants;
import com.wxy.favorites.core.PageInfo;
import com.wxy.favorites.entity.Category;
import com.wxy.favorites.entity.Password;
import com.wxy.favorites.security.ContextUtils;
import com.wxy.favorites.security.SecurityUser;
import com.wxy.favorites.service.CategoryService;
import com.wxy.favorites.service.FavoritesService;
import com.wxy.favorites.service.PasswordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/category")
@Api(tags = "分类")
@Secured("category")
public class CategoryController {

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private FavoritesService favoritesService;

    @Autowired
    private PasswordService passwordService;

    @PostMapping
    @ApiOperation(value = "保存分类")
    public Category save(@RequestBody Category category) {
        if (category.getId() == null) {// 新增
            return categoryService.saveCategory(category);
        } else {// 修改
            return categoryService.updateCategory(category);
        }
    }

    @GetMapping("/{id}")
    @ApiOperation(value = "根据id查询")
    public Category query(@PathVariable Integer id) {
        return categoryService.query(id);
    }

    @GetMapping("/setTop/{id}")
    @ApiOperation(value = "置顶")
    public Integer setTop(@PathVariable Integer id) {
        return categoryService.setTop(id);
    }

    @GetMapping("/check/{name}")
    @ApiOperation(value = "检查分类是否存在")
    public Boolean existName(@PathVariable String name) {
        return categoryService.existName(name);
    }

    @GetMapping("/updateCheck")
    @ApiOperation(value = "检查分类是否存在")
    public Boolean updateCheck(@RequestParam Integer id, @RequestParam String name) {
        return categoryService.updateCheck(id, name);
    }

    @GetMapping("/favorites/{categoryId}")
    @ApiOperation(value = "查询分类下的收藏")
    public Category favorites(@PathVariable Integer categoryId) {
        return categoryService.findCategory(categoryId);
    }

    /**
     * 删除分类
     *
     * @param id
     * @return
     */
    @GetMapping("/delete/{id}")
    @ApiOperation(value = "删除分类")
    public Boolean delete(@PathVariable Integer id) {
        return categoryService.delete(id);
    }

    @GetMapping("/moveDefault/{id}")
    @ApiOperation(value = "删除分类-移至默认")
    public Boolean moveDefault(@PathVariable Integer id) {
        return categoryService.moveDefault(id);
    }

    /**
     * 清空收藏
     *
     * @param id
     * @return
     */
    @PostMapping("/clean")
    @ApiOperation(value = "清空收藏")
    public Boolean clean(@RequestParam Integer id) {
        return categoryService.clean(id);
    }

    @GetMapping("/list")
    @ApiOperation(value = "查询分类列表")
    public List<Category> list() {
        SecurityUser user = ContextUtils.getCurrentUser();
        return categoryService.findByUserId(user.getId());
    }

    @PostMapping("/bookmark")
    @ApiOperation(value = "切换书签模式")
    public Boolean bookmark(@RequestBody Category category) {
        return categoryService.bookmark(category);
    }

    @GetMapping("/page")
    @ApiOperation(value = "分页查询")
    public PageInfo<Category> page(@RequestParam(required = false) String name, @RequestParam Integer pageNum, @RequestParam Integer pageSize) {
        SecurityUser user = ContextUtils.getCurrentUser();
        name = Optional.ofNullable(name).orElse("").trim().toLowerCase();// 转换小写搜索
        return categoryService.findPage(user.getId(), name, pageNum, pageSize);
    }

    @GetMapping("/export/{id}")
    @ApiOperation(value = "导出")
    public void export(HttpServletResponse response, @PathVariable Integer id) throws IOException, ParseException {
        // 查询用户分类
        Category category = categoryService.exportCategory(id);
        response.setContentType(ContentType.OCTET_STREAM.getValue());
        // 写入输出流
        writeXML(response.getOutputStream(), List.of(category));
    }

    private void writeXML(OutputStream out, List<Category> categories) throws IOException {
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement("DATA");
        if (!CollectionUtils.isEmpty(categories)) {
            Element categoriesList = root.addElement("CATEGORIES");
            categories.forEach(c -> {
                Element category = categoriesList.addElement("CATEGORY");
                category.addElement("NAME").setText(c.getName());
                if (c.getSort() != null) {
                    category.addElement("SORT").setText(String.valueOf(c.getSort()));
                }
                if (PublicConstants.BOOKMARK_STYLE_CODE.equals(c.getBookmark())) {
                    category.addElement("BOOKMARK").setText("true");
                }
                Element list = category.addElement("LIST");
                Optional.ofNullable(c.getFavorites()).orElse(Collections.emptyList()).forEach(f -> {
                    Element favorites = list.addElement("FAVORITES");
                    favorites.addElement("NAME").setText(f.getName());
                    favorites.addElement("URL").setText(f.getUrl());
                    favorites.addElement("ICON").setText(f.getIcon());
                    if (f.getSort() != null) {
                        favorites.addElement("SORT").setText(String.valueOf(f.getSort()));
                    }
                    if (PublicConstants.FAVORITES_STAR_CODE.equals(f.getStar())) {
                        favorites.addElement("STAR").setText("true");
                    }
                    if (PublicConstants.SHARE_CODE.equals(f.getIsShare())) {
                        favorites.addElement("SHARE").setText("true");
                    }
                    if (StrUtil.isNotBlank(f.getShortcut())) {
                        favorites.addElement("SHORTCUT").setText(f.getShortcut());
                    }
                    if (StrUtil.isNotBlank(f.getSchemaName())) {
                        favorites.addElement("SCHEMA_NAME").setText(f.getSchemaName());
                    }
                    if (f.getPassword() != null) {
                        Password password = f.getPassword();
                        Element pwd = favorites.addElement("USER");
                        pwd.addElement("ACCOUNT").setText(password.getAccount());
                        pwd.addElement("PASSWORD").setText(password.getPassword());
                    }
                });
            });
        }
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding(StandardCharsets.UTF_8.name());
        XMLWriter writer = new XMLWriter(out, format);
        writer.setEscapeText(true);
        writer.write(document);
        writer.close();
    }
}
